package me.goldze.mvvmhabit.binding.viewadapter.view

import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.databinding.BindingAdapter
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomViewTarget
import com.bumptech.glide.request.transition.Transition
import com.chengyi.serialport.demo.R
import com.chengyi.serialport.demo.utils.PictureSelectorHelp
import com.jakewharton.rxbinding4.internal.AlwaysTrue
import com.jakewharton.rxbinding4.internal.checkMainThread
import com.wyj.utils.AssetsUtil
import com.wyj.utils.MApplication
import com.wyj.utils.ReflectUtils
import io.reactivex.rxjava3.android.MainThreadDisposable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Observer
import me.goldze.mvvmhabit.binding.command.BindingAction
import me.goldze.mvvmhabit.binding.command.BindingCommand
import me.jessyan.autosize.utils.AutoSizeUtils
import java.util.concurrent.TimeUnit

object ViewAdapter {
    //防重复点击间隔(毫秒)
    private const val CLICK_INTERVAL = 400L

    private class ViewClickObservable(private val view: View) : Observable<View>() {
        override fun subscribeActual(observer: Observer<in View>) {
            if (!checkMainThread(observer)) {
                return
            }
            val listener = Listener(view, observer)
            observer.onSubscribe(listener)
            view.setOnClickListener(listener)
        }

        private class Listener(private val view: View, private val observer: Observer<in View>) : MainThreadDisposable(), View.OnClickListener {
            override fun onClick(v: View) {
                if (!isDisposed) {
                    observer.onNext(v)
                }
            }

            override fun onDispose() {
                view.setOnClickListener(null)
            }
        }
    }

    private class ViewLongClickObservable(private val view: View, private val handled: () -> Boolean) : Observable<View>() {
        override fun subscribeActual(observer: Observer<in View>) {
            if (!checkMainThread(observer)) {
                return
            }
            val listener = Listener(view, handled, observer)
            observer.onSubscribe(listener)
            view.setOnLongClickListener(listener)
        }

        private class Listener(private val view: View, private val handled: () -> Boolean, private val observer: Observer<in View>) : MainThreadDisposable(), View.OnLongClickListener {
            override fun onLongClick(v: View): Boolean {
                if (!isDisposed) {
                    try {
                        if (handled()) {
                            observer.onNext(v)
                            return true
                        }
                    } catch (e: Exception) {
                        observer.onError(e)
                        dispose()
                    }
                }
                return false
            }

            override fun onDispose() {
                view.setOnLongClickListener(null)
            }
        }
    }

    /**
     * requireAll 是意思是是否需要绑定全部参数, false为否
     * View的onClick事件绑定
     * onClickCommand 绑定的命令,
     * isThrottleFirst 是否开启防止过快点击
     */
    @JvmStatic
    fun onClickCommand(view: View, clickCommand: BindingCommand<Context>, isThrottleFirst: Boolean? = true) {
        ViewClickObservable(view).let { if (isThrottleFirst != false) it.throttleFirst(CLICK_INTERVAL, TimeUnit.MILLISECONDS) else it }.subscribe { clickCommand.execute(it.context) }
    }


    /**
     * requireAll 是意思是是否需要绑定全部参数, false为否
     * View的onClick事件绑定
     * onClickCommand 绑定的命令,
     * isThrottleFirst 是否开启防止过快点击
     */
    @JvmStatic
    @BindingAdapter(value = ["onClickCommand", "isThrottleFirst"], requireAll = false)
    fun onClickCommand(view: View, clickCommand: BindingAction, isThrottleFirst: Boolean? = true) {
        ViewClickObservable(view).let { if (isThrottleFirst != false) it.throttleFirst(CLICK_INTERVAL, TimeUnit.MILLISECONDS) else it }.subscribe { clickCommand.call() }
    }

    /**
     * view的onLongClick事件绑定
     */
    @JvmStatic
    @BindingAdapter(value = ["onLongClickCommand"], requireAll = false)
    fun onLongClickCommand(view: View, clickCommand: BindingAction) {
        ViewLongClickObservable(view, AlwaysTrue).subscribe { clickCommand.call() }
    }

    @BindingAdapter(value = ["selected"])
    @JvmStatic
    fun setSelected(view: View, selected: Boolean) {
        view.isSelected = selected
    }

    @BindingAdapter(value = ["previewImage"], requireAll = false)
    @JvmStatic
    fun previewImage(view: View, previewImage: String) {
        onClickCommand(view, BindingCommand { context ->
            if (context is Activity) {
                PictureSelectorHelp.startActivityPreview(context, previewImage)
            }
        })
    }

    @BindingAdapter(value = ["previewImageRes"], requireAll = false)
    @JvmStatic
    fun previewImageRes(view: View, previewImageRes: Drawable) {
        onClickCommand(view, BindingCommand { context ->
            PictureSelectorHelp.startActivityPreview(context, previewImageRes)
        })
    }

    /**
     * view是否需要获取焦点
     */
    @BindingAdapter("requestFocus")
    @JvmStatic
    fun requestFocusCommand(view: View, needRequestFocus: Boolean) {
        if (needRequestFocus) {
            view.isFocusableInTouchMode = true
            view.requestFocus()
        } else {
            view.clearFocus()
        }
    }

    @BindingAdapter("onFocusChangeCommand")
    @JvmStatic
    fun onFocusChangeCommand(view: View, onFocusChangeCommand: BindingCommand<Boolean>?) {
        view.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
            onFocusChangeCommand?.execute(hasFocus)
        }
    }

    @BindingAdapter(value = ["android:layout_width", "android:layout_height", "android:layout_gravity", "android:layout_margin"], requireAll = false)
    @JvmStatic
    fun setLayoutParams(view: View, width: String?, height: String?, gravity: Int?, margin: String?) {
        val lp = view.layoutParams ?: return
        var top = -1
        var right = -1
        var bottom = -1
        var left = -1
        val context = view.context
        val NaN = -10000
        val setWidthAnaHeight = { width: String?, height: String?, lp: ViewGroup.LayoutParams? ->
            val parse = { w: String? ->
                var v = NaN
                if (w?.endsWith("px") == true) {
                    v = w.replace("px", "").toIntOrNull() ?: -1
                } else if (w?.endsWith("dp") == true || w?.toFloatOrNull() != null) {
                    w.replace("dp", "").toFloatOrNull()?.let {
                        v = AutoSizeUtils.dp2px(view.context, it)
                    }
                }
                ViewGroup.LayoutParams.WRAP_CONTENT
                w?.toIntOrNull() ?: v
            }
            val w = parse(width)
            val h = parse(height)
            if (w != NaN) {
                lp?.width = w
            }
            if (h != NaN) {
                lp?.height = h
            }
        }
        margin?.split(",")?.let {
            if (it.size == 1) {
                val margin = AutoSizeUtils.dp2px(context, it[0].toFloat())
                top = margin
                right = margin
                bottom = margin
                left = margin
            } else if (it.size == 4) {
                top = AutoSizeUtils.dp2px(context, it[0].toFloat())
                right = AutoSizeUtils.dp2px(context, it[1].toFloat())
                bottom = AutoSizeUtils.dp2px(context, it[2].toFloat())
                left = AutoSizeUtils.dp2px(context, it[3].toFloat())
            }
        }
        when (lp) {
            is LinearLayout.LayoutParams -> {
                if (gravity != null) {
                    lp.gravity = gravity
                }
                if (top != -1 && right != -1 && bottom != -1 && left != -1) {
                    lp.leftMargin = left
                    lp.rightMargin = right
                    lp.topMargin = top
                    lp.bottomMargin = bottom
                }
                setWidthAnaHeight(width, height, lp)
                view.layoutParams = lp
            }
            is FrameLayout.LayoutParams -> {
                if (gravity != null) {
                    lp.gravity = gravity
                }
                if (top != -1 && right != -1 && bottom != -1 && left != -1) {
                    lp.leftMargin = left
                    lp.rightMargin = right
                    lp.topMargin = top
                    lp.bottomMargin = bottom
                }
                setWidthAnaHeight(width, height, lp)
                view.layoutParams = lp
            }
            else -> {
                setWidthAnaHeight(width, height, view.layoutParams)
                view.layoutParams = lp
            }
        }
    }


    @BindingAdapter("android:background")
    @JvmStatic
    fun setBackground(view: View, background: Any?) {
        when (background) {
            is Int -> {
                view.setBackgroundColor(background)
            }
            is Drawable -> {
                view.background = background
            }
            is Bitmap -> {
                view.background = BitmapDrawable(MApplication.application.resources, background)
            }
            is String -> {
                if (background.startsWith("@color/")) {
                    view.setBackgroundColor(ContextCompat.getColor(MApplication.application, ReflectUtils.getStaticClassField(R.color::class.java, background.replace("^@color/".toRegex(), "")) as Int))
                } else {
                    val url = when {
                        //assets文件使用一定要在build.gradle加上
                        // sourceSets {
                        //        main {
                        //            assets {
                        //                srcDirs = ["src/main/assets"]
                        //            }
                        //        }
                        //    }
                        //如果assets中有资源文件被更新（例如v1.apk和v2.apk都有a.png，但图片不一样）一定要在application中加context.cacheDir?.let { FileUtils.deleteFiles(it) }
                        background.startsWith("@/") -> background.replace("^@/".toRegex(), "${AssetsUtil.ROOT}images/")
                        //如果raw中有资源文件被更新（例如v1.apk和v2.apk都有a.png，但图片不一样）一定要在application中加context.cacheDir?.let { FileUtils.deleteFiles(it) }
                        background.startsWith("R/") -> background.replace("^R/".toRegex(), "android.resource://${view.context.packageName}/raw/")
                        background.startsWith("@drawable/") -> background.replace("^@drawable/".toRegex(), "android.resource://${view.context.packageName}/drawable/")
                        else -> background
                    }
                    Glide.with(view).load(url).into(object : CustomViewTarget<View, Drawable>(view) {
                        override fun onLoadFailed(errorDrawable: Drawable?) {

                        }

                        override fun onResourceCleared(placeholder: Drawable?) {
                        }

                        override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
                            view.background = resource
                        }
                    })
                }
            }
        }
    }

    @BindingAdapter("android:visibility")
    @JvmStatic
    fun setVisibility(view: View, visibility: Int) {
        view.visibility = visibility
    }

    @BindingAdapter("android:visibility")
    @JvmStatic
    fun setVisibility(view: View, visibility: Boolean) {
        setVisibility(view, if (visibility) View.VISIBLE else View.GONE)
    }
}